package com.tct.smartRE.fwk.impl.transform;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.tct.smartRE.fwk.api.IBusinessObject;
import com.tct.smartRE.fwk.api.IQueryCondition;
import com.tct.smartRE.fwk.api.transform.IDataTransformation;
import com.tct.smartRE.fwk.api.transform.event.IPostTransformationEvent;
import com.tct.smartRE.fwk.api.transform.event.IPreTransformationEvent;
import com.tct.smartRE.fwk.api.transform.event.ITransformationEvent;
import com.tct.smartRE.fwk.api.transform.event.ITransformationEventManager;
import com.tct.smartRE.fwk.impl.transform.TransformationConstant.ActionEnum;

public class DataTransformation implements IDataTransformation {

	private final ITransformationEventManager transformationEventManager;

	public DataTransformation(
			ITransformationEventManager transformationEventManager) {
		this.transformationEventManager = transformationEventManager;
	}

	public List<Map<String, Object>> deTransformForFind(
			List<IBusinessObject> objects) {

		if (objects == null) {
			return null;
		}
		List<Map<String, Object>> result = new ArrayList<Map<String, Object>>();

		for (IBusinessObject obj : objects) {
			Map<String, Object> deTransform = new HashMap<String, Object>();
			String eventPoint = obj.getClass().getSimpleName();

			// onPreDestruction event

			// onDestruction event
			ITransformationEvent transformationEvent = transformationEventManager
					.getTransformationEvent(eventPoint);
			if (transformationEvent == null) {
				// if having no transformationEvent with eventPoint ==> load
				// default
				transformationEvent = transformationEventManager
						.getTransformationEvent(TransformationConstant.EVENT_POINT_SYSTEM);
			}
			transformationEvent.onDestruction(obj, deTransform);

			// onPostDestruction event
			List<IPostTransformationEvent> postDestruction = transformationEventManager
					.getPostTransformationEvent(TransformationConstant.EVENT_POINT_SYSTEM);
			if (postDestruction != null && postDestruction.size() > 0) {
				for (IPostTransformationEvent iPostTransformationEvent : postDestruction) {
					iPostTransformationEvent
							.onPostDestructionEvent(deTransform);
				}
			}
			postDestruction = transformationEventManager
					.getPostTransformationEvent(eventPoint);
			if (postDestruction != null && postDestruction.size() > 0) {
				for (IPostTransformationEvent iPostTransformationEvent : postDestruction) {
					iPostTransformationEvent
							.onPostDestructionEvent(deTransform);
				}
			}

			result.add(deTransform);
		}

		return result;
	}

	public IQueryCondition transformForCount(Map<String, Object> source) {
		if (source == null) {
			return null;
		}
		String eventPoint = (String) source.get(TransformationConstant.CLASS_TYPE);
		// onPreConstructionEVent
		List<IPreTransformationEvent> preEvent = transformationEventManager
				.getPreTransformationEvent(eventPoint);
		for (IPreTransformationEvent iPreTransformationEvent : preEvent) {
			iPreTransformationEvent.onPreConstructionEvent(source);
		}
		
		// onConstructionEvent: getTransformationEvent
		ITransformationEvent event = transformationEventManager.getTransformationEvent(eventPoint);
		if(event == null) {
			event = transformationEventManager.getTransformationEvent(TransformationConstant.EVENT_POINT_SYSTEM);
		}
		if (source.get(TransformationConstant.ACTION) == null) {
			source.put(TransformationConstant.ACTION, ActionEnum.COUNT_ACTION);
		} else if (((ActionEnum) source.get(TransformationConstant.ACTION)) != ActionEnum.COUNT_ACTION) {
			throw new IllegalArgumentException("Action must be COUNT");
		}
		Map<String, Object> destination = new HashMap<String, Object>();
		event.onConstruction(source, destination);
		
		// onPostConstructionEVent
		List<IPostTransformationEvent> postEvent = transformationEventManager
				.getPostTransformationEvent(eventPoint);
		for (IPostTransformationEvent iPostTransformationEvent : postEvent) {
			iPostTransformationEvent.onPostConstructionEvent(destination);
		}
		
		return (IQueryCondition) destination.get(TransformationConstant.OBJECT);
	}
	
	public IQueryCondition transformForFind(Map<String, Object> source) {
		if (source == null) {
			return null;
		}
		String eventPoint = (String) source.get(TransformationConstant.CLASS_TYPE);

		// onPreConstructionEVent
		List<IPreTransformationEvent> preEvent = transformationEventManager
				.getPreTransformationEvent(eventPoint);
		for (IPreTransformationEvent iPreTransformationEvent : preEvent) {
			iPreTransformationEvent.onPreConstructionEvent(source);
		}

		// onConstructionEvent: getTransformationEvent
		ITransformationEvent transformationEvent = transformationEventManager
				.getTransformationEvent(eventPoint);
		if (transformationEvent == null) {
			transformationEvent = transformationEventManager
					.getTransformationEvent(TransformationConstant.EVENT_POINT_SYSTEM);
		}

		if (source.get(TransformationConstant.ACTION) == null) {
			source.put(TransformationConstant.ACTION, ActionEnum.FIND_ACTION);
		} else if (((ActionEnum) source.get(TransformationConstant.ACTION)) != ActionEnum.FIND_ACTION) {
			throw new IllegalArgumentException("Action must be FIND");
		}
		Map<String, Object> destination = new HashMap<String, Object>();
		transformationEvent.onConstruction(source, destination);

		// onPostConstructionEVent
		List<IPostTransformationEvent> postEvent = transformationEventManager
				.getPostTransformationEvent(eventPoint);
		for (IPostTransformationEvent iPostTransformationEvent : postEvent) {
			iPostTransformationEvent.onPostConstructionEvent(destination);
		}

		return (IQueryCondition) destination.get(TransformationConstant.OBJECT);
	}

	public IBusinessObject transformForSave(Map<String, Object> source) {
		if (source == null) {
			return null;
		}
		String eventPoint = (String) source.get(TransformationConstant.CLASS_TYPE);

		// onPreConstructionEvent: invoke pre transformation event
		List<IPreTransformationEvent> preEvents = transformationEventManager
				.getPreTransformationEvent(eventPoint);
		for (IPreTransformationEvent preEvent : preEvents) {
			preEvent.onPreConstructionEvent(source);
		}

		ITransformationEvent event = transformationEventManager.getTransformationEvent(eventPoint);
		if(event == null) {
			event = transformationEventManager.getTransformationEvent(TransformationConstant.EVENT_POINT_SYSTEM);
		}
		if (source.get(TransformationConstant.ACTION) == null) {
			source.put(TransformationConstant.ACTION, ActionEnum.EDIT_ACTION);
		} else if (((ActionEnum) source.get(TransformationConstant.ACTION)) != ActionEnum.EDIT_ACTION) {
			throw new IllegalArgumentException("Action must be EDIT");
		}
		Map<String, Object> destination = new HashMap<String, Object>();
		event.onConstruction(source, destination);	
		
		// onPostConstructionEvent: invoke post transformation event
		List<IPostTransformationEvent> postEvents = transformationEventManager
				.getPostTransformationEvent(eventPoint);
		for (IPostTransformationEvent postEvent : postEvents) {
			postEvent.onPostConstructionEvent(destination);
		}

		return (IBusinessObject) destination.get(TransformationConstant.OBJECT);
	}
}
